/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package app.utils;

import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ColorConvertOp;
import java.awt.image.Kernel;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;

/**
 *
 * @author bharat
 */
public class ImageUtils {
    /*
    public static Kernel makeNormalizedGaussianKernel(float sigma, int size){
        float[] kernelVal = new float[size*size] ;
        float val = 0.0f ;
        float sigma22 = 2*sigma*sigma;

        for (int y = size/2; y >= 0; --y)
         {
             for (int x = size/2; x >= 0; --x)
             {
              val = (float)Math.exp(-(float)(y*y+x*x)/sigma22);

              gaussianKernel.set(val, size/2-x, size/2-y);
              gaussianKernel.set(val, size/2-x, size/2+y);
              gaussianKernel.set(val, size/2+x, size/2-y);
              gaussianKernel.set(val, size/2+x, size/2+y);
             }
         }
    }
     */

    public static BufferedImage getGrayScaleImage(BufferedImage srcImg){
        BufferedImageOp op = new ColorConvertOp( ColorSpace.getInstance(ColorSpace.CS_GRAY),null);
        return op.filter(srcImg,null);
    }

    
    public static Kernel makeGaussinKernel1D(float sigma) {
        float radius = sigma * 3;
        int r = (int) Math.ceil(radius);
        int rows = r * 2 + 1;
        float[] matrix = new float[rows];
        float sigma22 = 2 * sigma * sigma;
        float sigmaPi2 = (float) (2 * Math.PI * sigma);
        float sqrtSigmaPi2 = (float) Math.sqrt(sigmaPi2);
        float radius2 = radius * radius;
        float total = 0;
        int index = 0;
        for (int row = -r; row <= r; row++) {
            float distance = row * row;
            if (distance > radius2) {
                matrix[index] = 0;
            } else {
                matrix[index] = (float) Math.exp(-(distance) / sigma22) / sqrtSigmaPi2;
            }
            total += matrix[index];
            index++;
        }
        for (int i = 0; i < rows; i++) {
            matrix[i] /= total;
        }

        return new Kernel(rows, 1, matrix);
    }

    public static Kernel makeGaussianKernel2D(float sigma) {
        float radius = sigma * 3;
        int r = (int) Math.ceil(radius);
        int rows = r * 2 + 1;

        float[] kernelVals = new float[rows*rows];

        float sigma22 = 2.0f * sigma * sigma;
        float oneBy2PiSigma2 = (float) (1.0f / ( Math.PI * sigma22)) ;
        float sum = 0.0f;
        float[] x2y2 = new float[rows*rows] ;

        float xDist = 0.0f, yDist = 0.0f ;

       for (int x=0; x < rows; x++){
           for (int y=0; y < rows; y++){
               xDist = Math.abs(x-((rows-1)/2)) ;
               yDist = Math.abs(y-((rows-1)/2)) ;
               x2y2[x*rows + y] = (xDist*xDist + yDist*yDist) / sigma22 ;
           }
       }

        for (int i=0; i< kernelVals.length; i++){
            kernelVals[i] = (float) (oneBy2PiSigma2 * Math.pow(Math.E, ( (-1) * x2y2[i]) )) ;
            sum += kernelVals[i] ;
        }

        for (int i=0; i< kernelVals.length; i++){
            kernelVals[i] /= sum ;
        }

        return new Kernel(rows, 1, kernelVals);
    }

    public static BufferedImage scaleImage(BufferedImage image, int width, int height) {
        int type = image.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : image.getType();
        BufferedImage resizedImage = new BufferedImage(width, height, type);
        Graphics2D g = resizedImage.createGraphics();
        g.setComposite(AlphaComposite.Src);

        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        g.drawImage(image, 0, 0, width, height, null);
        g.dispose();
        return resizedImage;
    }

    public static BufferedImage readImageStr(String fileName) {
        File f = new File(fileName);
        return readImage(f);
    }

    public static BufferedImage readImage(File f) {
        if (!f.exists()) {
            SiftLogger.log(Level.SEVERE, "Failed to read File from Location: " + f.getAbsolutePath());
        }
        BufferedImage img = null;
        InputStream is;

        try {

            is = new FileInputStream(f);
            img = ImageIO.read(is);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return img;
    }

    public static BufferedImage readRGBImageStr(String fileName, int width, int height) {
        File f = new File(fileName);
        return readRGBImage(f, width, height);
    }

    public static BufferedImage readRGBImage(File f, int width, int height) {
        if (!f.exists()) {
            SiftLogger.log(Level.SEVERE, "Failed to read File from Location: " + f.getAbsolutePath());
        }
        BufferedImage img = null;
        InputStream is;
        byte a,r,g,b ;

        try {
            img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            //img = ImageIO.read(f) ;

            is = new FileInputStream(f);

            // Read-in data from file
            long len = f.length();
            byte[] bytes = new byte[(int) len];

            int offset = 0;
            int numRead = 0;

            while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
                offset += numRead;
            }

            // Create the image
            if (img == null) {
                img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            }

            int ind = 0;
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {

                    a = 0;
                    r = bytes[ind];
                    g = bytes[ind + height * width];
                    b = bytes[ind + height * width * 2];

                    int pix = 0xff000000 | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff);

                    img.setRGB(x, y, pix);
                    ind++;
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            SiftLogger.log(Level.SEVERE, "Failed to read File from Location: " + e.getMessage());
            img = null;
        }
        return img;
    }
}
